package jmine.tec.services.utils.replace.hssf;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.utils.replace.api.ServiceBlock;
import jmine.tec.services.utils.replace.api.ServiceBlockContainer;
import jmine.tec.services.utils.replace.api.ServiceTransformation;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import bancosys.tec.services.input.XLSFileConstants;
import bancosys.tec.services.input.driver.xls.XLSUtils;
import bancosys.tec.services.input.exceptions.InputException;

public class HSSFServiceBlockContainer implements ServiceBlockContainer {
    private static final Logger LOGGER = LogManager.getLogger(HSSFServiceBlockContainer.class);

    private final HSSFWorkbook workbook;

    private final List<HSSFServiceBlock> blocks;

    public HSSFServiceBlockContainer(InputStream input) throws IOException, InputException {
        this.blocks = new ArrayList<HSSFServiceBlock>();
        this.workbook = this.createWorkbook(input);
        this.load();
    }

    /*
     * (non-Javadoc)
     * @see jmine.biz.invest.operacional.liquidacao.services.replace.ServiceBlockContainer#applyChanges()
     */
    public void persistChanges(OutputStream output) throws IOException {
        try {
            this.workbook.write(output);
        } catch (IOException e) {
            LOGGER.error("Não foi possível gravar no arquivo de saida.\n" + e.getStackTrace());
            throw e;
        } finally {
            output.close();
        }
    }

    public boolean applyTransformation(ServiceTransformation transformation) {
        return this.applyTransformations(Collections.singletonList(transformation));
    }

    public boolean applyTransformations(List<? extends ServiceTransformation> transformations) {
        boolean effect = false;
        for (ServiceBlock block : this.blocks) {
            for (ServiceTransformation transformation : transformations) {
                if (transformation.shouldApply(block)) {
                    effect = true;
                    System.out.println(String.format("Aplicando transformação %s em %s.", transformation, block));
                    transformation.apply(block);
                }
            }
        }
        return effect;
    }

    private HSSFWorkbook createWorkbook(InputStream input) throws IOException {
        try {
            return new HSSFWorkbook(input);
        } catch (IOException e) {
            LOGGER.error("Não foi possível abrir a planilha.\n" + e.getStackTrace());
            throw e;
        }
    }

    private void load() throws InputException {
        XLSUtils utils = new XLSUtils(this.workbook);
        for (int i = 0; i < this.workbook.getNumberOfSheets(); i++) {
            HSSFSheet sheet = this.workbook.getSheetAt(i);
            String sheetName = this.workbook.getSheetName(i);
            if (!sheetName.startsWith("NExec")) {
                List<HSSFRow> blockRows = new ArrayList<HSSFRow>();
                Iterator rowIterator = sheet.rowIterator();
                while (rowIterator.hasNext()) {
                    HSSFRow row = (HSSFRow) rowIterator.next();
                    String cellContents = utils.getCellContentAsString(sheetName, row, XLSFileConstants.ACTIONS_COLUMN);
                    String name = utils.getCellContentAsString(sheetName, row, XLSFileConstants.SERVICES_COLUMN);
                    String firstHeaderContents = utils.getCellContentAsString(sheetName, row, XLSFileConstants.RESERVED_COLUMNS);
                    if (cellContents.matches("^(\\-|\\+)?\\d+((\\.)?\\d*)?$")) {
                        // somente numeros na primeira coluna
                        continue;
                    }

                    if (StringUtils.isBlank(cellContents)) {
                        if (blockRows.size() > 1) {
                            this.blocks
                                    .add(new HSSFServiceBlock(sheetName, new XLSUtils(this.workbook), new ArrayList<HSSFRow>(blockRows)));
                        }
                        blockRows.clear();
                        if (!StringUtils.isBlank(firstHeaderContents)) {
                            blockRows.add(row);
                        }
                    } else if (ActionsEnum.isValid(cellContents)) {
                        /*
                         * A linha corrente representa uma acao a ser executada
                         */
                        ActionsEnum action = ActionsEnum.valueOf(cellContents);

                        if (action.getAllowedServicesCount() == -1 && blockRows.isEmpty()) {
                            continue;
                        } else if (!StringUtils.isBlank(name)) {
                            blockRows.add(row);
                        }

                    } else {
                        continue;
                    }
                }
                if (!blockRows.isEmpty()) {
                    this.blocks.add(new HSSFServiceBlock(sheetName, new XLSUtils(this.workbook), blockRows));
                }
            }
        }
    }

}
